#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <sys/reboot.h>
#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/if_ether.h>
#include <netinet/in.h>
#include <linux/sockios.h>
#include <net/route.h>
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <pthread.h>
#include <unistd.h>
#include <thread>
#include "aes.h"
#include "gvcpReg.h"
#include "sockgvcp.h"
#include "sockgvsp.h"
#include "gigeError.h"
#include "socktool.h"
#include "netconfig.h"
#include "iniconfig.h"
#include "cam_ctrl.h"
#include "gl7004.h"

using namespace std;

u8 xml_buf[15000000];
u32 line_rate=10000;
u32 exp_time=50;
u32 gain=1;
u32 offset=0;
u32 img_h=480;
u32 trig_mod=0x00;
u32 trig_src=0x01;
u32 trig_act=0x00;
u32 enc_mod=0x00;
u32 acq_en=0;

static u32  xml_path;
static u32  xml_size;
static u32  heart_time;
char current_host[32];

char m_szLocalIp[32]="172.5.5.99";
char m_szLocalMask[32]="255.255.0.0";
char m_szLocalGateway[32]="172.5.5.1";

char m_szRemoteIp[32];
char m_szRemoteMask[32];
char m_szRemoteGateway[32];
char m_szRemoteMac[32];
uint32 m_dwRemotePort;

u16 desPort;

u8  reg_spec[REG_CUST_BASE];
u32 reg_cust[REG_CUST_SIZE];

u32 reg_0x00020004;
u32 reg_0x00020204;
u32 reg_0x00020524;
u32 reg_0x00020544;
u32 reg_0x00020A24;
u32 reg_0x00030024;
u32 reg_0x00030204;
u32 reg_0x00040004;
u32 reg_0x00040024;
u32 reg_0x00040044;
u32 reg_0x00040144;
u32 reg_0x00040204;
u32 reg_0x00040224;
u32 reg_0x00040244;
u32 reg_0x00040424;
u32 reg_0x00040464;
u32 reg_0x00040484;
u32 reg_0xd0000004;
u32 reg_0xd0000008;
u32 reg_0xd000000c;
u32 reg_0xd0000010;
u32 reg_0xd0000014;
u32 reg_0xd0000454;
u32 reg_0xd0000458;
u32 reg_0xF2F07038;

void xml_read()
{
    FILE* fp = fopen(XML_FILE_NAME,"rb");
    fseek(fp, 0, SEEK_END);
    xml_size = ftell(fp);
    printf("XML_SIZE: %d\n",xml_size);
    fseek(fp, 0, SEEK_SET);
    fread(xml_buf, 1, xml_size, fp);
    fclose(fp);
}

void sock_init(int* sockfd, struct sockaddr_in* Addr)
{
    xml_read();
    int iOptval = 1;
    *sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    setsockopt(*sockfd, SOL_SOCKET, SO_BROADCAST | SO_REUSEADDR, (char*)&iOptval, sizeof(int));
    memset(Addr, 0, sizeof(struct sockaddr_in));
    Addr->sin_family = AF_INET;
    Addr->sin_addr.s_addr = INADDR_ANY;
    Addr->sin_port = htons(3956);
    bind(*sockfd, (struct sockaddr *)Addr, sizeof(*Addr));
}

void sock_send(int sockfd, unsigned char* rgMessage, char* m_szRemoteIp, u16 dwMsgLen, u16 dwPort)
{
    int iOptval = 1;
    struct sockaddr_in Addr;
    int bNeedClose = 0;
    if(sockfd < 0){
		sockfd = socket(AF_INET, SOCK_DGRAM, 0);
		bNeedClose=1;
	}
    setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST | SO_REUSEADDR, (char*)&iOptval, sizeof(int));
    memset(&Addr, 0, sizeof(struct sockaddr_in));
    Addr.sin_family = AF_INET;
    Addr.sin_addr.s_addr = inet_addr(m_szRemoteIp);
    Addr.sin_port = htons(dwPort);
    sendto(sockfd, rgMessage, dwMsgLen, 0, (struct sockaddr*)&Addr, sizeof(struct sockaddr));
    if(bNeedClose > 0) close(sockfd);
}

bool gvcp_same_subnet(in_addr *local, in_addr *mask, const in_addr *remote) {
    struct in_addr local_net;
    struct in_addr remote_net;

    local_net.s_addr  = local->s_addr  & mask->s_addr;
    remote_net.s_addr = remote->s_addr & mask->s_addr;

    return local_net.s_addr == remote_net.s_addr;
}

char *gvcp_discover_ip(struct in_addr remote)
{
    struct in_addr ip;
    struct in_addr mask;
    struct in_addr broadcast;

    broadcast.s_addr = INADDR_BROADCAST;

    net_eth_get_ipv4_addr(GVCP_DEV_NAME, (unsigned char *)&ip, (unsigned char *)&mask);

	if (gvcp_same_subnet(&ip, &mask, &remote))
	{
		return inet_ntoa(remote);
	}

	return inet_ntoa(broadcast);
}

char *gvcp_cam_name(void)
{
	static char cam_name[] = "ATV-L4KG-GM";

	return cam_name;
}

void gvcp_ack_discover(int sockfd, char* m_szRemoteIp, u16 desPort, u16 wReqID)
{
    struct in_addr remote;
    struct gvcp_discover_ack ack;
    memset(&ack, 0, sizeof(struct gvcp_discover_ack));

    ack.header.wStatus = htons(GEV_STATUS_SUCCESS);
    ack.header.wAck    = htons(GVCP_DISCOVERY_ACK);
    ack.header.wLen    = htons(sizeof(struct gvcp_ack_payload));
    ack.header.wAckID  = htons(wReqID);

    ack.payload.dwSpecVer = htonl(0x010001);
    ack.payload.dwDevMode = htonl(0x80000001);
    ack.payload.dwSupIpSet = htonl(0x00000007);
    ack.payload.dwCurIpSet = htonl(gvcp_read_reg(REG_CGIP));

    remote.s_addr = inet_addr(m_szRemoteIp);

    net_eth_get_mac(GVCP_DEV_NAME, (unsigned char *)ack.payload.Mac);
    net_eth_get_ipv4_addr(GVCP_DEV_NAME, (unsigned char *)&ack.payload.CurIP, (unsigned char *)&ack.payload.SubMask);
    net_route_get_default_gateway(GVCP_DEV_NAME, (unsigned char *)&ack.payload.Gateway);

    strcpy(ack.payload.szFacName,"BOQ");
	strcpy(ack.payload.szModelName, gvcp_cam_name());
	strcpy(ack.payload.szDevVer,"V3.1.14 190814 310211");
	strcpy(ack.payload.szFacInfo,"BOQ");
	//strcpy(ack.payload.szSerial,"00C31976084");
	ini_sn_get(ack.payload.szSerial);
    ini_userID_get(ack.payload.szUserName);

    printf("ACK: %s\n",m_szRemoteIp);
    unsigned int local_ip = ntohl(ack.payload.CurIP);
    sprintf(m_szLocalIp,"%d.%d.%d.%d", (local_ip >> 24)&0xff, (local_ip >> 16)&0xff, (local_ip >> 8)&0xff, local_ip&0xff);
    //printf("Local ip: %s\n",m_szLocalIp);
    sock_send(sockfd, (unsigned char*)&ack, gvcp_discover_ip(remote), sizeof(struct gvcp_discover_ack), desPort);
}

void gvcp_ack_forceip(int sockfd, char* m_szRemoteIp, u16 desPort, void *req)
{
    unsigned char  gw[4];
    unsigned char mac[6];
    struct in_addr CurIP;
    struct in_addr SubMask;
    struct in_addr Gateway;
    struct gvcp_ack_header ack;
    struct gvcp_forceip_cmd *cmd = (struct gvcp_forceip_cmd *) req;

    memcpy(&CurIP,   &cmd->CurIP,   sizeof(CurIP));
    memcpy(&SubMask, &cmd->SubMask, sizeof(SubMask));
    memcpy(&Gateway, &cmd->Gateway, sizeof(Gateway));

	printf("FORCEIP: %s\n",m_szRemoteIp);
	printf("ip: %s\n", inet_ntoa(CurIP));
	printf("netmask: %s\n", inet_ntoa(SubMask));

	net_eth_get_mac(GVCP_DEV_NAME, mac);

    if (memcmp(mac, cmd->Mac, 6))
    {
        printf("mac mismatched:%02X:%02X:%02X:%02X:%02X:%02X\n",
            cmd->Mac[0],
            cmd->Mac[1],
            cmd->Mac[2],
            cmd->Mac[3],
            cmd->Mac[4],
            cmd->Mac[5]);
        return;
    }

    if (gvcp_read_reg(REG_CGIP)&0x01)
    {
        // Keep to file
        set_static_ip(CurIP, SubMask, Gateway, mac);
    }
    net_eth_set_ipv4_addr(GVCP_DEV_NAME, (unsigned char *)&CurIP, (unsigned char *)&SubMask);
    /* modify gateway */
    net_route_get_default_gateway(GVCP_DEV_NAME, gw);
    net_route_del_default_gateway(GVCP_DEV_NAME, gw);
    net_route_add_default_gateway(GVCP_DEV_NAME, (unsigned char *)&Gateway);

    ack.wStatus = htons(GEV_STATUS_SUCCESS);
    ack.wAck    = htons(GVCP_FORCEIP_ACK);
    ack.wLen    = htons(0);
    ack.wAckID  = htons(cmd->header.wReqID);

    sock_send(sockfd, (unsigned char*)&ack, m_szRemoteIp, sizeof(struct gvcp_ack_header), desPort);
}

u32 gvcp_read_reg(u32 addr)
{
    u32 *reg;

    switch(addr)
    {
       case REG_CCP:
    	   //gvcp_heart_update(GVCP_DEF_TIME);
    	   break;
       case REG_SEN_TEMP:
    	   //reg_cust[addr-REG_CUST_BASE] = sensor_temp();
    	   break;
       case REG_PKT_LEN:
    	   reg_cust[addr-REG_CUST_BASE] = reg_cust[REG_AOI_WIDTH-REG_CUST_BASE]*reg_cust[REG_AOI_HEIGHT-REG_CUST_BASE];
           printf("REG_PKT_LEN:%d %d %d\n",reg_cust[addr-REG_CUST_BASE], reg_cust[REG_AOI_WIDTH-REG_CUST_BASE], reg_cust[REG_AOI_HEIGHT-REG_CUST_BASE]);
    	   break;
       case 0x40464:
    	   printf("exp_time:%d\n",exp_time);
    	   return exp_time;
       case 0x404a4:
    	   printf("line_rate:%d\n",line_rate);
    	   return line_rate;
       case 0x20a04:
       case 0x20a24:
    	   printf("gain:%d\n",gain);
    	   return gain;
       case 0x30224:
    	   printf("img_h:%d\n",img_h);
    	   return img_h;
       case 0x40244:
    	   printf("trig:%d\n",trig_src);
    	   return trig_src;
       default:
		   break;
    }

    if (addr < REG_CUST_BASE)
    {
         reg = (u32*)&reg_spec[addr];

        return *reg;
    }

    if (addr <= GVCP_REG_SIZE)
    {
        return reg_cust[addr-REG_CUST_BASE];
    }

    switch(addr)
    {
      case 0x0000B000:
    	  return 0x000003E8;
      case 0x0000B008:
    	  return 0x00000001;
      case 0x0000C000:
    	  return 0x000000DC;
      case 0x0000C004:
    	  return 0x00004014;
      case 0x0000C018:
    	  return 0x02FAF080;
      case 0x0000C00C:
    	  return 0x000067FA;
      case 0x0000C01C:
    	  return 0x0000000A;
      case 0x0000C024:
    	  return 0x00000043;
      case 0x0000C028:
    	  return 0x0000000A;
      case 0x0000C034:
    	  return 0x00000001;
      case 0x0000C038:
    	  return 0x00000001;
      case 0x0000C02C:
    	  return 0x00000001;
      case 0x0000C030:
    	  return 0x0000001B;
      case 0x0000C100:
    	  return 0x0B26DE9F;
      case 0x0000C104:
    	  return 0x06B492B5;
      case 0x0000C108:
    	  return 0x07735940;
      case 0x0000C10C:
    	  return 0x002ED8AA;
      case 0x00010000:
    	  return 0xF8000000;//return 0x80000000;
      case 0x00010008:
    	  return 0x00000502;
      case 0x00010020:
    	  return 0xF8000000;//return 0x80000000;
      case 0x00010028:
    	  return 0x00000402;
      case 0x00010088:
    	  return gvcp_read_reg(0x30224)*img_h;
      case 0x00013000:
    	  return 0xE8000000;//return 0x80000000;
      case 0x00013020:
    	  return 0xE8000000;//return 0x80000000;
      case 0x00020000: // Analog controls GainAuto
    	  return 0xE8000000;
      case 0x00020004:
    	  return reg_0x00020004;
      case 0x0002000C:
    	  return 0xE0000000;
      case 0x00020020: // Analog controls selector
    	  return 0xE8000000;
      case 0x00020200: // Analog controls BlackLevelRaw
    	  return 0xE8000000;
      case 0x00020204: // Analog controls BlackLevelRaw val
    	  return reg_0x00020204;
      case 0x00020208: // Analog controls BlackLevelRaw min
    	  return 0xFFFFFF80;
      case 0x0002020C: // Analog controls BlackLevelRaw max
    	  return 0x0000007F;
      case 0x00020400: // Color lmprovements Controls BalanceWhiteAuto
    	  return 0xE8000000;
      case 0x0002040C:
    	  return 0xE0000000;
      case 0x00020420:  // Color lmprovements Controls BalanceRatioSelector
    	  return 0xE8000000;
      case 0x00020424: // Color lmprovements Controls BalanceRatioRaw
    	  return 0x00000053;
      case 0x0002042C:
    	  return 0x000003FF;
      case 0x00020434: // Color lmprovements Controls BalanceRatioAbs
    	  return 0x00000006;
      case 0x00020440:
    	  return 0xE8000000;
      case 0x00020444:
    	  return 0x00000040;
      case 0x00020460:
    	  return 0xE8000000;
      case 0x00020464:
    	  return 0x0000005F;
      case 0x00020480: // Color lmprovements Controls BalanceWhiteReset
    	  return 0xE8000000;
      case 0x00020500: // Analog controls GammaEnable
    	  return 0xE8000000;
      case 0x00020504:
    	  return 0x00000001;
      case 0x00020520: // Analog controls Gamma
    	  return reg_0x00020544 == 1? 0xE8000000: 0xA8000000;
      case 0x00020524:
    	  return reg_0x00020524? reg_0x00020524: 0x00010000;
      case 0x0002052C:
    	  return 0x0003FFFF;
      case 0x00020534:
    	  return 0x00000010;
      case 0x00020540: // Analog controls GammaSelector
    	  return 0xE8000000;
      case 0x00020544:
    	  return reg_0x00020544? reg_0x00020544: 0x00000002;
      case 0x0002054C:
    	  return 0xE0000000;
      case 0x00020550:
    	  return 0xFFFFFFFF;
      case 0x00020600: // Analog controls DigitalShift
    	  return 0xE8000000;
      case 0x0002060C:
    	  return 0x00000002;
      case 0x00020610:
    	  return 0x00000001;
      case 0x00020A00: // Analog controls GainRaw
    	  return 0xE8000000;
      case 0x00020A0C:
    	  return 0x00000003;
      case 0x00020A10:
    	  return 0x00000001;
      case 0x00020A20:
    	  return 0xE8000000;
      case 0x00020A24:
    	  return reg_0x00020A24;
      case 0x00020A2C:
    	  return 0x0000005F;
      case 0x00020A30: // GainRaw Inc
    	  return 0x00000001;
	  case 0x00030020: // Image Format controls PixelFormat
		  return 0xE8000000;
	  case 0x00030024:
		  return 1;//reg_0x00030024? reg_0x00030024: 0x0000002B;
      case 0x0003002c:
    	  return 0x40180C00;
	  case 0x00030030:
		  return 0x00180000;
      case 0x000300A4: // Image Format controls PixelSize
    	  return 0x0000008;
      case 0x000300Ac:
    	  return 0x00888000;
      case 0x0003010C: // Image Format controls PixelColorFilter
    	  return 0xC0000000;
      case 0x00030120: // Image Format controls PixelDynamicRangeMin
    	  return 0xF8000000;
      case 0x00030140: // Image Format controls PixelDynamicRangeMax
    	  return 0xF8000000;
      case 0x00030148:
    	  return 0x000000FF;
      case 0x00030160: // Image Format controls TestImageSelector
    	  return 0xE8000000;
      case 0x0003016C:
    	  return 0xFE000000;
      case 0x00030200: // AOI controls width
    	  return 0xE8000000;
      case 0x00030204:
    	  return reg_0x00030204? reg_0x00030204: 4096;
      case 0x00030208:
    	  return 0x00000002;
      case 0x0003020C:
    	  return 4096;
      case 0x00030210:
    	  return 0x00000002;
      case 0x00030220: // AOI controls height
    	  return 0xE8000000;
      case 0x00030228:
    	  return 0x00000002;
      case 0x0003022C:
    	  return 10000;
      case 0x00030230:
    	  return 0x00000002;
      case 0x00030240: // AOI controls X offset
    	  return 0xE8000000;
      case 0x00030250:
    	  return 0x00000002;
      case 0x00030260: // AOI controls Y offset
    	  return 0xE8000000;
      case 0x00030270:
    	  return 0x00000002;
      case 0x00030280: // AOI controls center X
    	  return 0xE8000000;
      case 0x000302A0: // AOI controls center Y
    	  return 0xE8000000;
      case 0x000302C0: // Image Format controls ReverseX
    	  return 0xE8000000;
      case 0x000303A0: // AOI controls DecimationHorizontal
    	  return 0xE8000000;
      case 0x000303A4:
      case 0x000303A8:
    	  return 0x00000001;
      case 0x000303AC:
    	  return 0x00000020;
      case 0x000303B0:
    	  return 0x00000001;
      case 0x000303C0: // AOI controls DecimationHorizontal
    	  return 0xE8000000;
      case 0x000303C4:
      case 0x000303C8:
    	  return 0x00000001;
      case 0x000303CC:
    	  return 0x00000020;
      case 0x000303D0:
    	  return 0x00000001;
      case 0x00030368:
    	  return 0x00000500;
      case 0x00030388:
    	  return 0x00000400;
      case 0x00040004: // Acquisition Controls AcquisitionMode
    	  return reg_0x00040004? reg_0x00040004: 0x00000002;
      case 0x0004000C:
    	  return 0xE0000000;
      case 0x000400A0: // Acquisition Controls AcquisitionFrameCount
    	  return 0xE8000000;
      case 0x000400A4:
    	  return 0x00000001;
      case 0x000400A8:
    	  return 0x00000001;
      case 0x000400AC:
    	  return 0x000000FF;
      case 0x000400B0:
    	  return 0x00000001;
      case 0x0004010C: // Acquisition Controls TriggerMode
    	  return 0xC0000000;
      case 0x00040110: // Acquisition Controls TriggerSelector
    	  return 0xC0000000;
      case 0x00040144: // Acquisition Controls TriggerSource
    	  return reg_0x00040144;
      case 0x0004014C:
    	  return 0xC0000400;
      case 0x0004016C:
    	  return 0xC0000000;
      case 0x00040180: // Acquisition Controls TriggerDelayAbs
    	  return 0xE8000000;
      case 0x0004018C:
    	  return 0x05F5E100;
      case 0x0004020C: // Acquisition Controls TriggerMode
    	  return 0xC0000000;
      case 0x00040210:
    	  return 0xC0000000;
      case 0x00040220: // Acquisition Controls TriggerSoftware
    	  return 0xE8000000;
      case 0x00040244: // Acquisition Controls TriggerSource
    	  return 0x00000001;
      case 0x0004024C:
    	  return 0xC0000400;
      case 0x0004026C: // Acquisition Controls TriggerActivation
    	  return 0xC0000000;
      case 0x00040280: // Acquisition Controls TriggerDelayAbs
    	  return 0xE8000000;
      case 0x0004028C:
    	  return 0x05F5E100;
      case 0x00040404: // Acquisition Controls ExposureMode
    	  return 0x00000001;
      case 0x0004040C:
    	  return 0x40000000;
      case 0x00040420: // Acquisition Controls ExposureAuto
    	  return 0xE8000000;
      case 0x00040424:
    	  return reg_0x00040424;
      case 0x0004042C:
    	  return 0xE0000000;
      case 0x00040440: // Acquisition Controls ExposureTimeAbs
    	  return 0xF8000000;
      case 0x00040448:
    	  return 0x000003E8;
      case 0x00040460: // Acquisition Controls ExposureTimeRaw
    	  return 0xE8000000;
      case 0x00040464:
    	  return reg_0x00040464? reg_0x00040464:0x00001388;
      case 0x00040468:
    	  return 0x0000000A;
      case 0x0004046C:
    	  return 0x000DFA20;
      case 0x00040470:
    	  return 0x00000001;
      case 0x00040480: // Acquisition Controls AcquisitionFrameRateEnable
    	  return 0xE8000000;
      case 0x000404A0: // Acquisition Controls AcquisitionFrameRateAbs
    	  return 0xE8000000;
      case 0x000404A4:
    	  return 0x000186A0;
      case 0x000404A8:
    	  return 0x00000001;
      case 0x000404AC:
    	  return 0x000DFA20;
      case 0x00040500: // Acquisition Controls ResultingFramePeriodAbs
    	  return 0xF8000000;
      case 0x00040508: // Acquisition Controls ResultingFrameRateAbs
    	  return 0x00005FE7;
      case 0x000405E0: // Acquisition Controls AcquisitionStatusSelector
    	  return 0xB8000000;
      case 0x00040600:
    	  return 0xF8000000;
      case 0x00040660:
    	  return 0xF8000000;
      case 0x0004E020: // Acquisition Controls ReadoutTimeAbs
    	  return 0xF8000000;
      case 0x0004E028:
    	  return 0x000039AA;
      case 0x0005000C: // Counter and Timer Controls CounterResetSource
    	  return 0xD0000000;
      case 0x00050020: // Counter and Timer Controls CounterSelector
    	  return 0xE8000000;
      case 0x0005004C: // Counter and Timer Controls CounterResetSource
    	  return 0xD0000000;
      case 0x00050060: // Counter and Timer Controls CounterEventSource
    	  return 0xE8000000;
      case 0x00053F00: // Counter and Timer Controls TimerDelayTimebaseAbs
    	  return 0xE8000000;
      case 0x00053F04:
    	  return 0x00000001;
      case 0x00053F08:
    	  return 0x00000001;
      case 0x00053F0C:
    	  return 0x0000002B;
      case 0x00053F20: // Counter and Timer Controls TimerDurationTimebaseAbs
    	  return 0xE8000000;
      case 0x00053F24:
    	  return 0x00000001;
      case 0x00053F28:
    	  return 0x00000001;
      case 0x00053F2C:
    	  return 0x0000002B;
      case 0x00054000: // Counter and Timer Controls TimerDelayRaw
    	  return 0xE8000000;
      case 0x0005400C:
    	  return 0x00000FFF;
      case 0x00054010:
    	  return 0x00000001;
      case 0x00054020: // Counter and Timer Controls TimerDurationRaw
    	  return 0xE8000000;
      case 0x00054024:
    	  return 0x00000FFF;
      case 0x0005402C:
    	  return 0x00000FFF;
      case 0x00054030:
    	  return 0x00000001;
      case 0x00060000: // Configuration Sets UserSetLoad
    	  return 0xE8000000;
      case 0x00060020: // Configuration Sets UserSetSave
    	  return 0xE8000000;
      case 0x00060040: // Configuration Sets UserSetSelector
    	  return 0xE8000000;
      case 0x00060050:
    	  return 0xF0E00000;
      case 0x00060060: // Configuration Sets UserSetDefaultSelector
    	  return 0xE8000000;
      case 0x00060080: // Configuration Sets DefaultSetSelector
    	  return 0xE8000000;
      case 0x0006008C:
    	  return 0xF0000000;
      case 0x00060090:
    	  return 0xFFFFFFFF;
      case 0x000600A0: // User Defined Values
    	  return 0xE8000000;
      case 0x000600A8: // User Defined Values UserDefinedValue
    	  return 0x80000000;
      case 0x000600AC:
    	  return 0x7FFFFFFF;
      case 0x000600B0:
    	  return 0x00000001;
      case 0x000600C0: // User Defined Values UserDefinedValueSelector
    	  return 0xE8000000;
      case 0x00060100:
    	  return 0xE8000000;
      case 0x00060140:
    	  return 0xE8000000;
      case 0x00060180:
    	  return 0xE8000000;
      case 0x00070000: // Auto Function Parameters AutoTargetValue
    	  return 0xE8000000;
      case 0x00070004:
    	  return 0x00000080;
      case 0x00070008:
    	  return 0x00000002;
      case 0x0007000C:
    	  return 0x000000FD;
      case 0x00070020: // Auto Function Parameters AutoGainRawLowerLimit
    	  return 0xE8000000;
      case 0x0007002C:
    	  return 0x0000005F;
      case 0x00070030:
    	  return 0x00000001;
      case 0x00070044: // Auto Function Parameters AutoGainRawUpperLimit
    	  return 0x0000005F;
      case 0x0007004C:
    	  return 0x0000005F;
      case 0x00070050:
    	  return 0x00000001;
      case 0x00070060: // Auto Function Parameters AutoExposureTimeAbsLowerLimit
    	  return 0xE8000000;
      case 0x00070064:
    	  return 0x00000014;
      case 0x00070068:
    	  return 0x0000000A;
      case 0x0007006C:
    	  return 0x00055730;
      case 0x00070080: // Auto Function Parameters AutoExposureTimeAbsUpperLimit
    	  return 0xE8000000;
      case 0x00070084:
    	  return 0x00055730;
      case 0x00070088:
    	  return 0x00000014;
      case 0x0007008C:
    	  return 0x000DFA20;
      case 0x000700A0: // Auto Function Parameters AutoFunctionProfile
    	  return 0xE8000000;
      case 0x000700B0:
    	  return 0xFFFFFFFF;
      case 0x000700C0: // Auto Function Parameters GrayValueAdjustmentDampingRaw
    	  return 0xE8000000;
      case 0x000700C4:
    	  return 0x000002BC;
      case 0x000700CC:
    	  return 0x00000320;
      case 0x000700D0:
    	  return 0x00000001;
      case 0x000700D4: // Auto Function Parameters GrayValueAdjustmentDampingAbs
    	  return 0x0000000A;
      case 0x000700E0: // Auto Function Parameters BalanceWhiteAdjustmentDampingRaw
    	  return 0xE8000000;
      case 0x000700E4:
    	  return 0x000003E8;
      case 0x000700EC:
    	  return 0x000003E8;
      case 0x000700F0:
    	  return 0x00000001;
      case 0x000700F4: // Auto Function Parameters BalanceWhiteAdjustmentDampingAbs
    	  return 0x0000000A;
      case 0x00070100: // Auto Function Parameters AutoFunctionAOIOffsetX
    	  return 0xE8000000;
      case 0x00070110:
    	  return 0x00000001;
      case 0x00070120:
    	  return 0xE8000000;
      case 0x00070200: // Auto Function Parameters AutoFunctionAOIOffsetY
    	  return 0xE8000000;
      case 0x00070210:
    	  return 0x00000001;
      case 0x00070220:
    	  return 0xE8000000;
      case 0x00070300: // Auto Function Parameters AutoFunctionAOIWidth
    	  return 0xE8000000;
      case 0x00070304:
    	  return 0x00000500;
      case 0x00070308:
    	  return 0x00000001;
      case 0x0007030C:
    	  return 0x00000500;
      case 0x00070310:
    	  return 0x00000001;
      case 0x00070320:
    	  return 0xE8000000;
      case 0x00070324:
    	  return 0x00000500;
      case 0x00070400: // Auto Function Parameters AutoFunctionAOIHeight
    	  return 0xE8000000;
      case 0x00070404:
    	  return 0x00000400;
      case 0x00070408:
    	  return 0x00000001;
      case 0x0007040C:
    	  return 0x00000400;
      case 0x00070410:
    	  return 0x00000001;
      case 0x00070420:
    	  return 0xE8000000;
      case 0x00070424:
    	  return 0x00000400;
      case 0x00070500: // Auto Function Parameters AutoFunctionAOISelector AOI1
    	  return 0xE8000000;
      case 0x00070508: // Auto Function Parameters UsageIntensity and WhiteBalance and RedLightCorrection
    	  return 0x80000000;
      case 0x0007050C:
    	  return 0xC0000000;
      case 0x00070510:
    	  return 0xC0000000;
      case 0x00080000: // Remove Parameter limits
    	  return 0xE8000000;
      case 0x00080100: // Expert Feature Access ExpertFeatureEnable
    	  return 0xA8000000;
      case 0x00070520: // Auto Function Parameters AutoFunctionAOISelector AOI2
    	  return 0xE8000000;
      case 0x00090008: // LUT Controls LUTValueAll
    	  return 0x0000000C;
      case 0x00090028: // LUT Controls LUTValue
    	  return 0x0000000C;
      case 0x00090060: // LUT Controls LUTEnable
    	  return 0xE8000000;
      case 0x00090100: // LUT Controls LUTIndex
    	  return 0xE8000000;
      case 0x000A0000: // Chunk Data Streams
    	  return 0xE8000000;
      case 0x000A0020: // Chunk Data Streams ChunkEnable
    	  return 0xA8000000;
      case 0x000B0000: // Events Generation EventOverrun
    	  return 0xE8000000;
      case 0x000B0020: // Events Generation ExposureEnd
    	  return 0xE8000000;
      case 0x000B0060: // Events Generation FrameStartOvertrigger
    	  return 0xE8000000;
      case 0x000B0080: // Events Generation AcquisitionStartOvertrigger
    	  return 0xE8000000;
      case 0x000B00C0: // Events Generation FrameStart
    	  return 0xE8000000;
      case 0x000B00E0: // Events Generation AcquisitionStart
    	  return 0xE8000000;
      case 0x000B0100: // Events Generation EventSelector
    	  return 0xE8000000;
      case 0x000B0120: // Events Generation
    	  return 0xE8000000;
      case 0x000B04C0: // Events Generation FrameWait
    	  return 0xE8000000;
      case 0x000B04E0: // Events Generation AcquisitionWait
    	  return 0xE8000000;
      case 0x000C000C: // Digital l/0 Controls LineMode
    	  return 0x80000000;
      case 0x000C0020: // Digital l/0 Controls LineInverter
    	  return 0xE8000000;
      case 0x000C0040: // Digital l/0 Controls LineSelector
    	  return 0xF8000000;
      case 0x000C0084: // Digital l/0 Controls LineFormat
    	  return 0x00000005;
      case 0x000C008C:
    	  return 0x04000000;
      case 0x000C00A0: // Digital l/0 Controls LineDebouncerTimeRaw
    	  return 0xE8000000;
      case 0x000C00A4:
    	  return 0x00002710;
      case 0x000C00AC:
    	  return 0x01312D00;
      case 0x000C00B0:
    	  return 0x00000001;
      case 0x000C0340: // Digital l/0 Controls SyncUserOutputSelector
    	  return 0xA0000000;
      case 0x000C0540:
    	  return 0xA0000000;
      case 0x000C0740:
    	  return 0xA0000000;
      case 0x000C0804: // Digital l/0 Controls LineMode
    	  return 0x00000001;
      case 0x000C080C:
    	  return 0x40000000;
      case 0x000C0820: // Digital l/0 LineInverter
    	  return 0xE8000000;
      case 0x000C0840:
    	  return 0xF8000000;
      case 0x000C0860: // Digital l/0 LineSource
    	  return 0xE8000000;
      case 0x000C086C:
    	  return 0xE1002060;
      case 0x000C0884:
    	  return 0x00000005;
      case 0x000C088C:
    	  return 0x04000000;
      case 0x000C08E0: // Digital l/0 Controls UserOutputValue
    	  return 0xE8000000;
      case 0x000C0900: // Digital l/0 Controls MinOutPulseWidthRaw
    	  return 0xE8000000;
      case 0x000C0940: // Digital l/0 Controls SyncUserOutputValue
    	  return 0xE8000000;
      case 0x000C0B40: // Digital l/0 Controls SyncUserOutput2
    	  return 0xA0000000;
      case 0x000C0D40:
    	  return 0xA0000000;
      case 0x000C0F40:
    	  return 0xA0000000;
      case 0x000C1940:
    	  return 0xA0000000;
      case 0x000C3000: // Digital l/0 Controls LineStatusAll
    	  return 0xF8000000;
      case 0x000C3020: // Digital l/0 Controls UserOutputValueAll
    	  return 0xE8000000;
      case 0x000C3040: // Digital l/0 Controls SyncUserOutputValueAll00000000000000002
    	  return 0xE8000000;
      case 0x000E0000: // Color lmprovements Controls LightSourceSelector
    	  return 0xE8000000;
      case 0x000E0004:
    	  return 0x00000002;
      case 0x000E000C:
    	  return 0xF2000000;
      case 0x000E0010:
    	  return 0xF2000000;
      case 0x000E0020: // Color lmprovements Controls ColorTransformationSelector
    	  return 0xA8000000;
      case 0x000E0040:
    	  return 0xA8000000;
      case 0x000E0060:
    	  return 0xA8000000;
      case 0x000E0080:
    	  return 0xA8000000;
      case 0x000E00A0:
    	  return 0xA8000000;
      case 0x000E00C0:
    	  return 0xA8000000;
      case 0x000E00E0:
    	  return 0xA8000000;
      case 0x000E0100:
    	  return 0xA8000000;
      case 0x000E0120:
    	  return 0xA8000000;
      case 0x000E0400: // Color lmprovements Controls ColorTransformationMatrixFactorRaw
    	  return 0xE8000000;
      case 0x000E0404:
    	  return 0x00010000;
      case 0x000E040C:
    	  return 0x00010000;
      case 0x000E0410:
    	  return 0x00000001;
      case 0x000E0414: // Color lmprovements Controls ColorTransformationMatrixFactor
    	  return 0x00000010;
      case 0x000E1000: // Color lmprovements Controls ColorAdjustmentEnable
    	  return 0xE8000000;
      case 0x000E1020: // Color lmprovements Controls ColorAdjustmentReset
    	  return 0xA8000000;
      case 0x000E1040: // Color lmprovements Controls ColorAdjustmentSelector
    	  return 0xA8000000;
      case 0x000E1060: // Color lmprovements Controls ColorAdjustmentHueRaw
    	  return 0xA8000000;
      case 0x000E1080: // Color lmprovements Controls ColorAdjustmentSelector
    	  return 0xA8000000;
      case 0x000E10C0:
    	  return 0xA8000000;
      case 0x000E1100:
    	  return 0xA8000000;
      case 0x000E1140:
    	  return 0xA8000000;
      case 0x000E1180:
    	  return 0xA8000000;
      case 0x000E2000: // Image Format controls ProcessedRawEnable
    	  return 0xA8000000;
      case 0x00120004: // Acquisition Controls ShutterMode
    	  return 0x00000002;
      case 0x0012000c:
    	  return 0xE0000000;
      case 0x00120020: // Image Quality
    	  return 0xE8000000;
      case 0x00130000: // Sequence Control SequenceEnable
    	  return 0xE8000000;
      case 0x00130020: // Sequence Control SequenceSetLoad
    	  return 0xE8000000;
      case 0x00130040: // Sequence Control SequenceSetStore
    	  return 0xE8000000;
      case 0x00130060: // Sequence Control SequenceSetTotalNumber
    	  return 0xE8000000;
      case 0x00130064:
    	  return 0x00000002;
      case 0x00130068:
    	  return 0x00000001;
      case 0x0013006C:
    	  return 0x00000040;
      case 0x00130070:
    	  return 0x00000001;
      case 0x00130080: // Sequence Control SequenceSetIndex
    	  return 0xE8000000;
      case 0x0013008C:
    	  return 0x00000001;
      case 0x00130090:
    	  return 0x00000001;
      case 0x001300A0: // Sequence Control SequenceSetExecutions
    	  return 0xE8000000;
      case 0x001300A4:
    	  return 0x00000001;
      case 0x001300A8:
    	  return 0x00000001;
      case 0x001300AC:
    	  return 0x00000100;
      case 0x001300B0:
    	  return 0x00000001;
      case 0x00130200: // Sequence Control SequenceAdvanceMode
    	  return 0xE8000000;
      case 0x0013020C:
    	  return 0xE0000000;
      case 0x00130210:
    	  return 0xE0000000;
      case 0x00130220: // Sequence Control SequenceAsyncRestart
    	  return 0xA8000000;
      case 0x00130240: // Sequence Control SequenceAsyncAdvance
    	  return 0xA8000000;
      case 0x00130260: // Sequence Control SequenceCurrentSet
    	  return 0xB8000000;
      case 0x00130400: // Sequence Control SequenceControlSelector
    	  return 0xA8000000;
      case 0x0013040C:
    	  return 0xA0000000;
      case 0x00130420:
    	  return 0xA8000000;
      case 0x00130440:
    	  return 0xA8000000;
      case 0x00130460:
    	  return 0xA8000000;
      case 0x00130500: // Sequence Control SequenceAddressBitSelector
    	  return 0xA8000000;
      case 0x0013050C:
    	  return 0x20000000;
      case 0x00130520:
    	  return 0xA8000000;
      case 0x00130540:
    	  return 0xA8000000;
      case 0x00130560:
    	  return 0xA8000000;
      case 0x00170000: // Feature Sets
    	  return 0xE8000000;
      case 0x0017000C: // Feature Sets GenicamXmlFileDefault
    	  return 0x00000001;
      case 0xB0002014: // Device Control DeviceRegistersStreamingStart
    	  return 0xA8000000;
      case 0xB0002034: // Device Control DeviceRegistersStreamingEnd
    	  return 0xA8000000;
      case 0xd0000000:
    	  return 0x40000200;
      case 0xd0000010:
    	  return reg_0xd0000010;
      case 0xd0000458:
    	  return 0x78000000 + reg_0xd0000458;
      case 0xd000045c:
    	  return 0x0100E000;
      case 0xd0000460:
    	  return 0xD8000000;
      case 0xd0000464:
    	  return 0x00200000;
      case 0xf2f01010:
    	  return 0x80080000;
      case 0xF2F07030: // Expert Feature Access ExpertFeatureAccessKey
    	  return 0xE0000000;
      case 0xF2F07034:
    	  return 0x0EDC0EDC;
      case 0xF2F07038:
    	  return reg_0xF2F07038? reg_0xF2F07038: 0x20000000;
      case 0xfffffff0:
    	  return 0x80000000;
      default: break;
    }

    return 0;
}

void gvcp_ack_readreg(int sockfd, char* m_szRemoteIp, u16 desPort, void *req)
{
    u32 addr;
    struct gvcp_readreg_cmd *cmd = (struct gvcp_readreg_cmd *) req;
    struct gvcp_readreg_ack *ack = (struct gvcp_readreg_ack*)malloc(sizeof(struct gvcp_ack_header) + htons(cmd->header.wLen));
    memset(ack, 0, sizeof(struct gvcp_ack_header) + htons(cmd->header.wLen));

    ack->header.wStatus = htons(GEV_STATUS_SUCCESS);
    ack->header.wAck    = htons(GVCP_READREG_ACK);
    ack->header.wLen    = cmd->header.wLen;
    ack->header.wAckID  = cmd->header.wReqID;

    for (int i = 0; i < htons(cmd->header.wLen) / sizeof(u32); i++)
    {
        /* Warning: do not use addr = cmd->dwRegAddr[i];
        *  Because riscv mcu need to align with the data type size of these variables.
        */
        memcpy(&addr, &cmd->dwRegAddr[i], sizeof(addr));
        ack->dwRegValue[i] = ntohl(gvcp_read_reg(htonl(addr)));
    }
    //printf("READREG: %s %x %x\n",m_szRemoteIp, htonl(addr), htonl(ack->dwRegValue[0]));
    //printf("%x %x %d %d\n", reg_spec[0x0D00],reg_spec[0x0D01],reg_spec[0x0D01]*256+reg_spec[0x0D00],*(u16*)(reg_spec+0x0D00));
    sock_send(sockfd, (unsigned char*)ack, m_szRemoteIp, sizeof(struct gvcp_readreg_ack) + htons(cmd->header.wLen), desPort);
    free(ack);
}

void gvcp_packet_resend(int sockfd, char* m_szRemoteIp, u16 desPort, void *req)
{
    struct gvcp_packet_resend_cmd *cmd = (struct gvcp_packet_resend_cmd *) req;

    thread t_resend(gvsp_resend, htons(cmd->payload.blockId), htonl(cmd->payload.firstPktId), htonl(cmd->payload.lastPktId), *(u32*)&reg_spec[REG_SCPS0]);
	t_resend.detach();

    printf("%s %d %d %d\n", __func__, htons(cmd->payload.blockId), htonl(cmd->payload.firstPktId), htonl(cmd->payload.lastPktId));
}

void reboot_handler(int sig) {
    printf("Executing system reboot...\n");
    sync();
    if(reboot(RB_AUTOBOOT) == -1) {
        perror("reboot failed");
        exit(EXIT_FAILURE);
    }
}

u32 gvcp_write_reg(u32 addr, u32 val)
{
    u32 *reg;

    switch(addr)
    {
	  case REG_LINE_RATE_VAL:
		  line_rate = val;
		  set_line_rate(line_rate);
		  printf("line_rate:%d\n",line_rate);
		  break;
      case REG_EXP_VAL:
          exp_time = val;
          set_exp_time(exp_time);
          printf("exp_time:%d\n",exp_time);
		  break;
	  case REG_AOI_HEIGHT:
		  img_h = val;
		  break;
    }

    if (addr < REG_CUST_BASE)
    {
         reg = (u32*)&reg_spec[addr];
        *reg = val; 

        return GEV_STATUS_SUCCESS;
    }

    if (addr <= GVCP_REG_SIZE)
    {
        reg_cust[addr-REG_CUST_BASE] = val; 

        return GEV_STATUS_SUCCESS;
    }

    switch(addr)
    {
	  case 0x00020004:
		  reg_0x00020004 = val;
		  return GEV_STATUS_SUCCESS;
	  case 0x00020204:
		  reg_0x00020204 = val;
		  return GEV_STATUS_SUCCESS;
	  case 0x00020524:
		  reg_0x00020524 = val;
		  return GEV_STATUS_SUCCESS;
	  case 0x00020544:
		  reg_0x00020544 = val;
		  return GEV_STATUS_SUCCESS;
	  case 0x00020A24:
		  reg_0x00020A24 = val;
		  return GEV_STATUS_SUCCESS;
      case 0x00030024:
    	  reg_0x00030024 = val;
    	  return GEV_STATUS_SUCCESS;
      case 0x00030204:
    	  reg_0x00030204 = val;
    	  return GEV_STATUS_SUCCESS;
      case 0x00040004:
  	      reg_0x00040004 = val;
  	      return GEV_STATUS_SUCCESS;
      case 0x00040024:
  	      reg_0x00040024 = val;
  	      return GEV_STATUS_SUCCESS;
      case 0x00040044:
  	      reg_0x00040044 = val;
  	      return GEV_STATUS_SUCCESS;
      case 0x00040144:
  	      reg_0x00040144 = val;
  	      return GEV_STATUS_SUCCESS;
      case 0x00040204:
  	      reg_0x00040204 = val;
  	      return GEV_STATUS_SUCCESS;
      case 0x00040224:
  	      reg_0x00040224 = val;
  	      return GEV_STATUS_SUCCESS;
      case 0x00040244:
  	      reg_0x00040244 = val;
  	      return GEV_STATUS_SUCCESS;
      case 0x00040424:
  	      reg_0x00040424 = val;
  	      return GEV_STATUS_SUCCESS;
      case 0x00040464:
  	      reg_0x00040464 = val;
  	      return GEV_STATUS_SUCCESS;
      case 0x00040484:
  	      reg_0x00040484 = val;
  	      return GEV_STATUS_SUCCESS;
      case 0xd0000004:
  	      reg_0xd0000004 = val;
  	      return GEV_STATUS_SUCCESS;
      case 0xd0000008:
    	  reg_0xd0000008 = val;
    	  return GEV_STATUS_SUCCESS;
      case 0xd000000c:
    	  reg_0xd000000c = val;
  	      return GEV_STATUS_SUCCESS;
      case 0xd0000014:
    	  reg_0xd0000014 = val;
  	      return GEV_STATUS_SUCCESS;
      case 0xd0000454:
    	  reg_0xd0000454 = val;
    	  return GEV_STATUS_SUCCESS;
      case 0xF2F07038:
    	  reg_0xF2F07038 = val;
    	  return GEV_STATUS_SUCCESS;
      case 0xfffffff0:
    	  return GEV_STATUS_SUCCESS;
      default: break;
    }

    printf("ERROR: write reg %x overflow range 0~%x\r\n", addr, GVCP_REG_SIZE);

    return GEV_STATUS_INVALID_ADDRESS;
}

static u16 gvcp_setup_reg(char *desAddr, u32 addr, u32 val)
{
    u16 res = GEV_STATUS_SUCCESS;

    switch (addr)
    {
        case REG_CGIP:
        {
            unsigned char   mac[6];
            struct in_addr   CurIP;
            struct in_addr SubMask;
            struct in_addr Gateway;

            net_eth_get_mac(GVCP_DEV_NAME, mac);
            if (val&0x02)
            {
              set_udhcpc_ip(mac);
            }
            if (val&0x01)
            {
              net_eth_get_ipv4_addr(GVCP_DEV_NAME, (unsigned char *)&CurIP, (unsigned char *)&SubMask);
              net_route_get_default_gateway(GVCP_DEV_NAME, (unsigned char *)&Gateway);
              set_static_ip(CurIP, SubMask, Gateway, mac);
            }
            break;
        }
       case REG_HRTT:
            printf("REG_HRTT: %x\r\n", val);
            break;
        case REG_CCP:
            printf("REG_CCP: %x\r\n", val);
            break;
        case REG_SCP0:
            printf("REG_SCP0: %x\r\n", val);
            break;
        case REG_SCPS0:
            printf("REG_SCPS0: %x\r\n", val);
            break;
        case REG_SCDA0:
            printf("REG_SCDA0: %x\r\n", val);
            break;

        case REG_BLKL_VAL:
            offset = val;
            set_offset(val);
        	break;
        case REG_GAMMA_CTL:
        	if (val)
        	{
        		break;
        	}
        	break;
        case REG_GAMMA_VAL:
        	break;
        case 0x00020544:
        case REG_GAMMA_SEL:
        	break;
        case REG_AOI_WIDTH:
        	 break;
        case REG_AOI_HEIGHT:
        	 break;
        case REG_AOI_XOFFSET:
        	 break;
        case REG_AOI_YOFFSET:
        	break;
        case REG_AOI_XCENTER:
        	break;
        case REG_AOI_YCENTER:
        	break;
        case REG_BINNINGH_VAL:
        	break;
        case REG_BINNINGV_VAL:
        	break;
        case REG_TRG_CTL:
        {
        	if (val)
        	{
                trig_mod = 1;
                set_trig_source(trig_src);
                printf("trigger on\n");
        		break;
        	}
            trig_mod = 0;
            set_trig_source(0);
            printf("trigger off\n");
        	break;
        }
        case REG_TRG_SRC:
        {
          trig_src = val;
          if(trig_mod == 1) set_trig_source(val);
          printf("trigger:%x\n",val);
          break;
        }
        case REG_TRG_ACT:
        {
            trig_act = val;
            set_trig_act(val);
        	break;
        }
        case REG_TRG_EXE:
        {
        	break;
        }
        case REG_TRG_DLY_VAL:
        	break;
        case REG_IO1_DEB:
        	break;
        case 0x00040024:
        case 0x00040044:
        case REG_ACQ_CTL:
        {
            if (val)
            {
                u16     port;
                in_addr dest;
                dest.s_addr = htonl(gvcp_read_reg(REG_SCDA0));
                       port = gvcp_read_reg(REG_SCP0) & 0xFFFF;
                desPort = port;
                printf("REG_ACQ_CTL: %x %s %d\r\n", val, inet_ntoa(dest), port);
                
                set_remote_port(port);
                set_local_ip(m_szLocalIp);
                set_local_mac();
                set_remote_ip_mac(m_szRemoteIp);
                set_img_h(img_h);
                set_pkt(*(u32*)&reg_spec[REG_SCPS0], img_h);

                axi_write_reg(CAM_CTRL_BASEADDR, IMG_STREAM_RST, 1);
                dma_init(img_h);
                axi_write_reg(CAM_CTRL_BASEADDR, IMG_STREAM_RST, 0);

                acq_en = 1;
                break;
            }
            acq_en = 0;
            break;
        }
        case REG_PIX_FMT:
        	break;
        case REG_REVERSEX:
            set_x_rev(val);
        	break;
        case REG_REVERSEY:
            set_y_rev(val);
        	break;
        case REG_TDI_MODE:
            set_tdi(val);
        	break;
        case REG_AWB_AUTO:
        	break;
        case REG_AWB_RED:
        	break;

        case REG_AWB_GRE:
        	break;

        case REG_AWB_BUE:
        	break;
        case REG_TRI_SEL:
        	break;
        case REG_FLAT_CTL:
            if(val == 0){
                fpn_reset();
                prnu_reset();
            }
            else if(val == 1){
                fpn_load();
                prnu_load();
            }
            else if(val == 2){
                fpn_reset();
                prnu_reset();
                FILE* fp = fopen("fpn.coe","w");
                for(int i=0;i<=4095;i++) fprintf(fp,"%d \n", 0);
                fclose(fp);
                fp = fopen("prnu.coe","w");
                for(int i=0;i<=4095;i++) fprintf(fp,"%d \n", 1024);
                fclose(fp);    
            }
        	break;
        case REG_FLAT_FPNC:
        {
            printf("FPNC\n");
            thread tfpn(fpn_set);
	        tfpn.detach();
            printf("FPNC finish\n");
        	break;
        }  
        case REG_FLAT_PRNUC:
        {
            printf("PRNU\n");
            thread tprnu(prnu_set);
	        tprnu.detach();
            printf("PRNU finish\n");
        	break;
        }
        case REG_PRNUC_TGT_EN:

        	break;
        case REG_PRNUC_TGT_VAL:

        	break;
        case REG_FREQ_DIV_VAL:

        	break;
        case REG_ENCODER_MODE:
            enc_mod = val;
            set_enc_mod(enc_mod);
        	break;
        case 0x00040464:
        case REG_EXP_VAL:
        {
        	exp_time = val;
        	set_exp_time(val);
        	printf("exp_time:%d\n",exp_time);
        	break;
        }
        case 0x000404a4:
            line_rate = val;
            set_line_rate(line_rate);
            printf("line_rate:%d\n",line_rate);
            break;
        case 0x00020a04:
        case 0x00020A24:
        case REG_ALG_GAIN:
            gain = val;
            set_gain(gain*10);
            printf("gain:%d\n",gain);
            break;
        case 0x00030224:
            img_h = val;
            printf("img_h:%d\n",img_h);
            break;
        case REG_TRIGR_CNT_RST:
        	//gvsp_trigr_count_reset();
        	break;
        case REG_FRAME_CNT_RST:
        	//gvsp_frame_count_reset();
        	break;
        case REG_USER_SET_SAVE:
        	//gvcp_reg_save(val);
        	break;
        case REG_USER_SET_DEF:
        	//nv_user_defID_set(val, true);
        	break;
        case REG_USER_SET_LOAD:
        	//gvcp_write_reg(REG_USER_SET_CUR, val);
        	//gvcp_reg_load(val);
        	break;
        case REG_CHUNK_TIMESTAMP:
        	//gvsp_chunk_timestamp_config(val);
        	break;
        case REG_CHUNK_FRAME_CNT:
        	//gvsp_chunk_frame_counter_config(val);
        	break;
        case REG_CHUNK_TRIGR_CNT:
        	//gvsp_chunk_trigr_counter_config(val);
        	break;
        case 0xd000000c:
             //gvcp_file_operation(val);
             break;
        case 0x00020004:
        case 0x00020204:
        case 0x00020524:
        case 0x00030024:
        case 0x00030204:
        case 0x00040004:
        case 0x00040144:
        case 0x00040424:
        case 0x00040484:
        case 0xd0000004:
        case 0xd0000008:
        case 0xd0000014:
        case 0xd0000454:
           printf("wr: addr %x val %x\r\n", addr, val);
           break;
        case 0xF2F07038:
           break;
        case 0xfffffff0:
           if (val & 0x01)
           {
             signal(SIGALRM, reboot_handler);
             alarm(3);
           }
        	break;
        default:
            if (addr > GVCP_REG_SIZE)
            {
                res = GEV_STATUS_INVALID_ADDRESS;
                printf("Invalid address: %x\r\n", addr);
            }
            break;
    }

    if (GEV_STATUS_SUCCESS == res)
    {
       res = gvcp_write_reg(addr, val);
    }

    return res;
}

void gvcp_ack_writereg(int sockfd, char* m_szRemoteIp, u16 desPort, void *req)
{
    u32    addr;
    u32   value;
    u16   index;
    u16  result;

    struct gvcp_writereg_cmd *cmd = (struct gvcp_writereg_cmd *) req;
    struct gvcp_writereg_ack *ack = (struct gvcp_writereg_ack*)malloc(sizeof(struct gvcp_writereg_ack));
    memset(ack, 0, sizeof(struct gvcp_writereg_ack));

    ack->header.wAck    = htons(GVCP_WRITEREG_ACK);
    ack->header.wLen    = htons(sizeof(ack->res) + sizeof(ack->index));
    ack->header.wAckID  = cmd->header.wReqID;

    for ( index = 0; index < htons(cmd->header.wLen) / sizeof(struct gvcp_writereg); index++)
    {
        /* Warning: do not use addr = cmd->reg[index].dwRegAddr;
        *  Because riscv mcu need to align with the data type size of these variables.
        */
        memcpy(&addr,  &cmd->reg[index].dwRegAddr,  sizeof(addr));
        memcpy(&value, &cmd->reg[index].dwRegValue, sizeof(value));

        result = gvcp_setup_reg(m_szRemoteIp, ntohl(addr), ntohl(value));
    }

    ack->index = htons(index);
    ack->header.wStatus = htons(result);
    printf("WRITEREG: %s %x %x\n",m_szRemoteIp, htonl(addr), htonl(value));
    sock_send(sockfd, (unsigned char*)ack, m_szRemoteIp, sizeof(struct gvcp_writereg_ack), desPort);
    free(ack);
}

u32 gvcp_pix_mask(void)
{
	GVCP_PIX_MASK_REG_T reg;

	reg.mask.mono8 = 1;

	return reg.value;
}

void gvcp_reg_init(void)
{
	u8 mac[6];
	u16  macH;
	u32  macL;
	u32 SetIP;

	net_eth_get_mac(GVCP_DEV_NAME, (unsigned char *)mac);
	SetIP = get_udhcpc_on()? 6: 5;

	memcpy(&macH, &mac[0], sizeof(u16));
	memcpy(&macL, &mac[2], sizeof(u32));

    gvcp_write_reg(REG_VER  ,       0x10001);
    gvcp_write_reg(REG_DEV  ,    0x80000001);
    gvcp_write_reg(REG_MACH ,   htons(macH));
    gvcp_write_reg(REG_MACL ,   htonl(macL));
    gvcp_write_reg(REG_SCDA0,             0);
    gvcp_write_reg(REG_SCP0 ,    0x00000000); //remote port
    gvcp_write_reg(REG_SCPS0,    0x000005dc); //LSB is size,=1500
    gvcp_write_reg(REG_SCPD0,             0);
	gvcp_write_reg(REG_MCDA ,             0);
	gvcp_write_reg(REG_MCTT ,             0);
	gvcp_write_reg(REG_MCRC ,             0);
	gvcp_write_reg(REG_MCSP ,             0);
    gvcp_write_reg(REG_SCSP0, GVSP_UDP_PORT);
    gvcp_write_reg(REG_CAIP ,             7);
    gvcp_write_reg(REG_CGIP ,         SetIP);
    gvcp_write_reg(REG_CPCP ,    0xFE00004E);
    gvcp_write_reg(REG_HRTT , GVCP_DEF_TIME);
    gvcp_write_reg(REG_TTFL ,    0x07735940);
    gvcp_write_reg(REG_NONI ,             1);
    gvcp_write_reg(REG_NOMC ,             1);
    gvcp_write_reg(REG_NOSC ,             1);
    gvcp_write_reg(REG_NOAS ,             1);
    gvcp_write_reg(REG_SPCP ,    0x80000000);
    gvcp_write_reg(REG_MSCP ,    0x00000000);

    gvcp_write_reg(N704 ,                 1);
	gvcp_write_reg(N1211,                 1);
	gvcp_write_reg(N410 ,                 1);
	gvcp_write_reg(N147 ,                 1);
	gvcp_write_reg(N165 ,        0x0210001F);
	gvcp_write_reg(N696 ,                 1);
	gvcp_write_reg(N1047,            0xFFFF);
	gvcp_write_reg(N755 ,            0x00DC);
	gvcp_write_reg(N756 ,            0x4014);
	gvcp_write_reg(N760 ,            0x67FA);
	gvcp_write_reg(N761 ,                 1);
	gvcp_write_reg(N3   ,                 0); //ok

	gvcp_write_reg(N333 ,        0xe8000000); //ok
    gvcp_write_reg(REG_AOI_WIDTH ,     4096);
	gvcp_write_reg(N337 ,               0x2); //ok W min
	gvcp_write_reg(N338 ,              4096); //ok W max
	gvcp_write_reg(N339 ,               0x2); //ok inc

	gvcp_write_reg(N340 ,        0xe8000000);
    gvcp_write_reg(REG_AOI_HEIGHT,      480);
	gvcp_write_reg(N344 ,                 2); //ok H min
	gvcp_write_reg(N345 ,             10000); //ok H max
	gvcp_write_reg(N346 ,                 2); //ok inc

    // aravis xml
    gvcp_write_reg(N408 ,                 0);
    gvcp_write_reg(N409 ,                 1);
    gvcp_write_reg(N410 ,              2222);
    gvcp_write_reg(N411 ,                 0);
    gvcp_write_reg(N413 ,                 0);
    gvcp_write_reg(N414 ,                 0);


	gvcp_write_reg(N463 ,        0xE8000000); //ok exp once
	gvcp_write_reg(N468 ,                 0); //ok exp continute

	gvcp_write_reg(N469 ,        0xE8000000); //ok ExposureTimeRaw
	gvcp_write_reg(REG_EXP_VAL ,         50);
	gvcp_write_reg(N473 ,                10); //ok exp time min
	gvcp_write_reg(N474 ,            900000); //ok exp time max
	gvcp_write_reg(N475 ,                 1); //ok exp time inc

	gvcp_write_reg(N486 ,        0x40000000); //exp mode
	gvcp_write_reg(N490 ,                 1);

	gvcp_write_reg(N1141,                 0);
	gvcp_write_reg(N1142,        0x000003e8); //exp abs val
	gvcp_write_reg(N1143,        0xf8000000); //exp abs val

	gvcp_write_reg(N509 ,        0xf8000000); //exp read out
 
	gvcp_write_reg(N502 ,                 0); //ExposureOverlapTimeMaxRaw
	gvcp_write_reg(N504 ,                 0);
	gvcp_write_reg(N505 ,                 0);
	gvcp_write_reg(N506 ,                 0);
	gvcp_write_reg(N507 ,                 0);
  
	gvcp_write_reg(N514 ,        0xf8000000); //AcquisitionStatusSelector
	gvcp_write_reg(N515 ,                 0);
	gvcp_write_reg(N516 ,                 0);
	gvcp_write_reg(N517 ,        0xf8000000);
	gvcp_write_reg(N518 ,                 0);
	gvcp_write_reg(N519 ,                 0);
	gvcp_write_reg(N520 ,                 0);
	gvcp_write_reg(N521 ,        0xb8000000);

	gvcp_write_reg(N2000,        0xc0000400);
	gvcp_write_reg(N1999,        0xc0000400);
	gvcp_write_reg(N1998,               0x1);
	gvcp_write_reg(N1997,               0x1);
	gvcp_write_reg(N1996,               0x0);
	gvcp_write_reg(N1995,        0xE8000000);
	gvcp_write_reg(N1994,               0x0);
	gvcp_write_reg(N1993,                 0);
	gvcp_write_reg(N1992,        0xc0000000);
	gvcp_write_reg(N1991,        0xc0000000);

	gvcp_write_reg(N1990,                 0);
	gvcp_write_reg(N1899,                 0);
	gvcp_write_reg(N100 ,        0xe8000000); //auto gain
	gvcp_write_reg(N105 ,                 2); //gain index,0:off,1:once,2:continue
	gvcp_write_reg(N1374,                 1);

	gvcp_write_reg(N347 ,        0xe8000000); //aoi offset 
	gvcp_write_reg(N350 ,                 0); //offset x
	gvcp_write_reg(N351 ,                 0); //min
	gvcp_write_reg(N352 ,                 0); //max
	gvcp_write_reg(N353 ,                 2); //inc

	gvcp_write_reg(N354 ,        0xe8000000);
	gvcp_write_reg(N357 ,                 0); //offset y
	gvcp_write_reg(N358 ,                 0); //min
	gvcp_write_reg(N359 ,                 0); //max
	gvcp_write_reg(N360 ,                 2); //lnc
	gvcp_write_reg(N528 ,        0x40000000);
	gvcp_write_reg(N529 ,        0x80000000);
	gvcp_write_reg(N578 ,                 1);
	gvcp_write_reg(N558 ,            100000);
	gvcp_write_reg(N981,                  1);
	gvcp_write_reg(N987,                  1);
	gvcp_write_reg(N1278,           0x3F0FF); // ChunkEnable lock map

	gvcp_write_reg(REG_PRNUC_TGT_VAL,        1024);
	gvcp_write_reg(REG_PRNUC_TGT_MIN,           0);
	gvcp_write_reg(REG_PRNUC_TGT_MAX,        4095);
	gvcp_write_reg(REG_PRNUC_TGT_INC,           1);
	gvcp_write_reg(REG_FREQ_DIV_VAL,            1);
	gvcp_write_reg(REG_FREQ_DIV_MIN,            1);
	gvcp_write_reg(REG_FREQ_DIV_MAX,          128);
	gvcp_write_reg(REG_FREQ_DIV_INC,            1);
	gvcp_write_reg(REG_BLKL_MIN,                0);
	gvcp_write_reg(REG_BLKL_VAL,                0);
	gvcp_write_reg(REG_BLKL_MAX,              128);
	gvcp_write_reg(REG_GAMMA_CTL,               1);
	gvcp_write_reg(REG_GAMMA_VAL,           10000);
	gvcp_write_reg(REG_GAMMA_MIN,               0);
	gvcp_write_reg(REG_GAMMA_MAX,           40000);
	gvcp_write_reg(REG_GAMMA_SEL,      GAMMR_SRGB);
	gvcp_write_reg(REG_DIGSHT_MAX,              2);
	gvcp_write_reg(REG_SEN_WIDTH,            4096);
	gvcp_write_reg(REG_SEN_HEIGHT,           4000);
	gvcp_write_reg(REG_BINVMODE_IMP,   0xC0000000);
	gvcp_write_reg(REG_BINHMODE_IMP,   0xC0000000);
	gvcp_write_reg(REG_BINNINGV_IMP,   0x80000000);
	gvcp_write_reg(REG_BINNINGV_VAL,            1);
	gvcp_write_reg(REG_BINNINGV_MIN,            1);
	gvcp_write_reg(REG_BINNINGV_MAX,            2);
	gvcp_write_reg(REG_BINNINGV_INC,            1);
	gvcp_write_reg(REG_BINNINGH_IMP,   0x80000000);
	gvcp_write_reg(REG_BINNINGH_VAL,            1);
	gvcp_write_reg(REG_BINNINGH_MIN,            1);
	gvcp_write_reg(REG_BINNINGH_MAX,            2);
	gvcp_write_reg(REG_BINNINGH_INC,            1);
	gvcp_write_reg(REG_TRG_SRC,                 1);
	gvcp_write_reg(REG_TRG_DLY_MAX,      10000000);
    gvcp_write_reg(REG_PIX_FMT,         FMT_MONO8); // pixcel format
    gvcp_write_reg(REG_PIX_MSK,   gvcp_pix_mask()); // pixcel mask
    gvcp_write_reg(REG_LITSRC_SEL,              6);
	gvcp_write_reg(REG_DEB_MAX,            200000);
	gvcp_write_reg(REG_IO1_DEB,                20);
    gvcp_write_reg(REG_ALG_GAIN_MAX,           10);
    gvcp_write_reg(REG_FRM_CNT_VAL,             1);
    gvcp_write_reg(REG_FRM_CNT_MIN,             1);
    gvcp_write_reg(REG_FRM_CNT_MAX,            32);
    gvcp_write_reg(REG_FRM_CNT_INC,             1);
    gvcp_write_reg(REG_LINE_RATE_VAL,       10000);
    gvcp_write_reg(REG_LINE_RATE_MIN,         100);
    gvcp_write_reg(REG_LINE_RATE_MAX,       29000);
    gvcp_write_reg(REG_SCAN_TYPE,               1);
}

void gvcp_ack_readmem(int sockfd, char* m_szRemoteIp, u16 desPort, void *req)
{
    u32 addr;
    u32 size;
    u16 count;
    struct gvcp_readmem_cmd *cmd = (struct gvcp_readmem_cmd *) req;
    size  = sizeof(struct gvcp_readmem_ack) + ntohs(cmd->dwMemCount);
    struct gvcp_readmem_ack *ack = (struct gvcp_readmem_ack*)malloc(size);
    count = ntohs(cmd->dwMemCount);

    memset(ack, 0, size);
    memcpy(&addr, &cmd->dwMemAddr, sizeof(addr));

    addr = ntohl(addr);
    ack->header.wStatus = htons(GEV_STATUS_SUCCESS);
    ack->header.wAck    = htons(GVCP_READMEM_ACK);
    ack->header.wLen    = htons(ntohs(cmd->dwMemCount) + sizeof(addr));
    ack->header.wAckID  = cmd->header.wReqID;
    ack->dwMemAddr      = htonl(addr);

    switch (addr)
    {
        case REG_URL1:
        case REG_URL2:
            //sprintf(ack->pMemBuf,"Local:%s;%08x;%x",XML_FILE_NAME, xml_path, xml_size);
            sprintf((char*)(ack->pMemBuf),"Local:%s;%08x;%x",XML_FILE_NAME, 0xc0000000, xml_size);
            break;
        case REG_MACH:
        {
            unsigned char mac[6];

            get_config_mac(mac);
            memcpy(ack->pMemBuf, mac, GIGE_MIN(count, 6));
            break;
        }
        case 0x48:
        case 0xa8:
        {
            memcpy(ack->pMemBuf, VENDOR_NAME, strlen(VENDOR_NAME));
        }
        break;
        case 0x68:
        {
            strcpy((char*)ack->pMemBuf, gvcp_cam_name());
        }
        break;
        case MEM_SN:
        case REG_SNUM:
        {
            char sn[16];

            ini_sn_get(sn);
            memcpy(ack->pMemBuf, sn, GIGE_MIN(count, 10));
            break;
        }
        case REG_USID:
        {
            char id[33];

            ini_userID_get(id);
            memcpy(ack->pMemBuf, id, GIGE_MIN(count, 32));
            break;
        }
        case REG_KEYID:
        {
            char str[33] = {0};
            char key[17] = {0};

            ini_key_get(str);
            hex_to_bytes(str, key, 16);
            if (count == 16)
            {
              memcpy(&ack->pMemBuf[0], key, 16);
              boq_aes_encrypt(ack->pMemBuf, 16, (uint8_t*)key);
              break;
            }
            ack->header.wStatus = htons(GEV_STATUS_BAD_ALIGNMENT);
            break;
        }
        case 0x88:
        case 0xf2f01014:
        {
            memcpy(ack->pMemBuf, SW_VERSION, strlen(SW_VERSION));
            break;
        }
        default:

        if (addr >= 0xc0000000 && addr <= 0xc0000000 + xml_size)
        {
            memcpy(ack->pMemBuf, xml_buf+addr-0xc0000000, ntohs(cmd->dwMemCount));
            break;
        }

        ack->header.wStatus = htons(GEV_STATUS_NOT_IMPLEMENTED);
        printf("%s ERROR Not Implemented Address %x\r\n", __func__, addr);
        break;
    }
    sock_send(sockfd, (unsigned char*)ack, m_szRemoteIp, size, desPort);
    free(ack);
}

void gvcp_ack_writemem(int sockfd, char* m_szRemoteIp, u16 desPort, void *req)
{
    u32 addr;
    u32 size;
    struct gvcp_writemem_cmd *cmd = (struct gvcp_writemem_cmd *) req;
    struct gvcp_writemem_ack *ack = (struct gvcp_writemem_ack*)malloc(sizeof(struct gvcp_writemem_ack));

    memset(ack, 0, sizeof(struct gvcp_writemem_ack));
    memcpy(&addr, &cmd->dwMemAddr, sizeof(addr));

    addr = ntohl(addr);
    size = htons(cmd->header.wLen) - sizeof(cmd->dwMemAddr);

    ack->header.wStatus = htons(GEV_STATUS_SUCCESS);
    ack->header.wAck    = htons(GVCP_WRITEMEM_ACK);
    ack->header.wLen    = htons(sizeof(ack->res) + sizeof(ack->index));
    ack->header.wAckID  = cmd->header.wReqID;
    ack->index          = htons(size);

    switch (addr)
    {
        case REG_MACH:
        {
            struct in_addr   CurIP;
            struct in_addr SubMask;
            struct in_addr Gateway;

            if (gvcp_read_reg(REG_CGIP)&0x02)
            {
              set_udhcpc_ip(cmd->pMemBuf);
            }
            if (gvcp_read_reg(REG_CGIP)&0x01)
            {
              net_eth_get_ipv4_addr(GVCP_DEV_NAME, (unsigned char *)&CurIP, (unsigned char *)&SubMask);
              net_route_get_default_gateway(GVCP_DEV_NAME, (unsigned char *)&Gateway);
              set_static_ip(CurIP, SubMask, Gateway, cmd->pMemBuf);
            }
            break;
        }
        case REG_SNUM:
        {
            char sn[11] = {0};
            memcpy(sn, cmd->pMemBuf, GIGE_MIN(size, 10));
            ini_sn_set(sn);
            break;
        }
        case REG_USID:
        {
            char id[33] = {0};

            memcpy(id, cmd->pMemBuf, GIGE_MIN(size, 32));
        	ini_userID_set(id);
        	break;
        }
        case REG_KEYID:
        {
            char str[33] = {0};
            char key[17] = {0};
            memcpy(key, cmd->pMemBuf, GIGE_MIN(size, 16));
            bytes_to_hex(key,16, str);
            ini_key_set(str);
            break;
        }
        case MEM_TYPE:
            break;
        case 0xd0000014:
            break;
        default:
            ack->header.wStatus = htons(GEV_STATUS_NOT_IMPLEMENTED);
            printf("%s ERROR Not Implemented Address %x\r\n", __func__, addr);
            break;
    }
    sock_send(sockfd, (unsigned char*)ack, m_szRemoteIp, sizeof(struct gvcp_writemem_ack), desPort);
    free(ack);
}

bool gvcp_packet_valid(struct gvcp_cmd_header *hdr, int length)
{

    if (hdr)
    {
        if (length < GVCP_MIN_SIZE)
        {
            printf("ERROR packet size %d less than %d", length, GVCP_MIN_SIZE);
            return false;
        }

        if (hdr->cMsgKeyCode != GVCP_KEY_CODE)
        {
            printf("ERROR key code %d not equal to 0x%x", hdr->cMsgKeyCode, GVCP_KEY_CODE);
            return false;
        }

        return true;
    }
    
    printf("%s: ERROR buffer is NULL", __func__);

    return false;
}

void gvcp_loop()
{
    int sockfd;
    int iRecvLen;
	int iAddrLength;
	u8 rgMessage[2014];
	struct sockaddr_in Addr;

	sock_init(&sockfd, &Addr);
	iAddrLength = sizeof(Addr);

    gvcp_reg_init();

	while (1)
    {
		iRecvLen = recvfrom(sockfd, rgMessage, sizeof(rgMessage), 0, (struct sockaddr *)&Addr, (socklen_t*)&iAddrLength);

		strncpy(m_szRemoteIp, inet_ntoa(Addr.sin_addr), 16);
		m_dwRemotePort = ntohs(Addr.sin_port);
		
		struct gvcp_cmd_header* pHeader = (struct gvcp_cmd_header*)rgMessage;
		static struct gvcp_cmd_header m_CmdHeader;

		m_CmdHeader.cMsgKeyCode = pHeader->cMsgKeyCode;// 0x42;
		m_CmdHeader.cFlag = pHeader->cFlag;//0x11 allow broadcast ack;ack required
		m_CmdHeader.wCmd = ntohs(pHeader->wCmd);//discovery_cmd=2;FORCEIP_CMD = 4;READREG_CMD=0x80
		m_CmdHeader.wLen = ntohs(pHeader->wLen);//payload length
		m_CmdHeader.wReqID = ntohs(pHeader->wReqID);// request id = 1;READREG id=12345

        if (gvcp_packet_valid(pHeader, iRecvLen))
        {
            switch (m_CmdHeader.wCmd)
            {
              case GVCP_DISCOVERY_CMD:
                  gvcp_ack_discover(sockfd, m_szRemoteIp, m_dwRemotePort, m_CmdHeader.wReqID);
                  break;
              case GVCP_READREG_CMD:
                  gvcp_ack_readreg(sockfd, m_szRemoteIp, m_dwRemotePort, rgMessage);
                  break;
              case GVCP_PACKETRESEND_CMD:
                  gvcp_packet_resend(sockfd, m_szRemoteIp, m_dwRemotePort, rgMessage);
                  break;
              case GVCP_WRITEREG_CMD:
                  gvcp_ack_writereg(sockfd, m_szRemoteIp, m_dwRemotePort, rgMessage);
                  break;
              case GVCP_READMEM_CMD:
                  gvcp_ack_readmem(sockfd, m_szRemoteIp, m_dwRemotePort, rgMessage);
                  break;
              case GVCP_WRITEMEM_CMD:
                  gvcp_ack_writemem(sockfd, m_szRemoteIp, m_dwRemotePort, rgMessage);
                  break;
              case GVCP_FORCEIP_CMD:
                  gvcp_ack_forceip(sockfd, m_szRemoteIp, m_dwRemotePort, rgMessage);
                  break;
              default:
                  break;
            }
        }
	}
}
